package point

import (
	"context"
	"fmt"
	"math"
	"sort"
	"strings"
	"time"

	"go.mongodb.org/mongo-driver/mongo"
)

// ---------------- 标签组合生成 ----------------
func primeFactorization(n int) (factors map[int]int) {
	factors = make(map[int]int, 0)
	if n == 1 {
		factors[n] = 1
		return
	}

	i := 2
	for n != 1 {

		if n%i == 0 {
			n = n / i
			factors[i] += 1
		} else {
			i++
		}

	}

	return
}

func tagCardinalityPartition(numTags int, factors map[int]int) []int {
	buckets := make([]int, numTags)

	for i := range buckets {
		buckets[i] = 1
	}

	orderedFactors := []int{}
	for factor, _ := range factors {
		orderedFactors = append(orderedFactors, factor)
	}
	sort.Ints(orderedFactors)

	i := 0
	for _, factor := range orderedFactors {
		power := factors[factor]
		buckets[i%len(buckets)] *= int(math.Pow(float64(factor), float64(power)))
		i++
	}

	return buckets
}

func sliceMod(m int, mods []int) []interface{} {
	res := make([]interface{}, len(mods))
	for i, mod := range mods {
		res[i] = m % mod
	}
	return res
}

func formatTemplate(s string) (string, int, []string) {
	if strings.HasPrefix(s, "tags=") {
		s = strings.TrimPrefix(s, "tags=")
	}
	parts := strings.Split(s, ",")
	numTags := len(parts)
	for i := 0; i < len(parts); i++ {
		parts[i] = parts[i] + "-%v"
	}
	return strings.Join(parts, ","), numTags, strings.Split(s, ",")
}

func generateSeriesKeys(template string, totalSeries int) []map[string]string {
	fmtTmplt, numTags, tags := formatTemplate(template)
	seriesList := make([]map[string]string, totalSeries)

	for i := 0; i < totalSeries; i++ {
		values := make([]interface{}, numTags)
		for j, tag := range tags {
			if tag == "sensor" {
				values[j] = i // sensor 严格唯一
			} else {
				values[j] = i % 10 // 其他 tag 可以重复组合，比如 region
			}
		}

		s := fmt.Sprintf(fmtTmplt, values...)
		parts := strings.Split(s, ",")
		m := make(map[string]string)
		for j, tag := range tags {
			m[tag] = parts[j]
		}

		seriesList[i] = m
	}

	return seriesList
}

// ---------------- MongoDB 插入 ----------------

func InsertPoints(collection *mongo.Collection, points []*Point) error {
	docs := make([]interface{}, len(points))
	for i, p := range points {
		doc := make(map[string]interface{})
		for k, v := range p.Tags {
			doc[k] = v
		}
		for k, v := range p.FieldsMap {
			doc[k] = v
		}
		doc["timestamp"] = p.Timestamp
		docs[i] = doc
	}
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	_, err := collection.InsertMany(ctx, docs)
	return err
}
